package com.googlecode.tda367.denty.core.dynamicbody;

import static com.googlecode.tda367.denty.constants.DynamicConstant.VELOCITY_H_INC;
import static com.googlecode.tda367.denty.constants.DynamicConstant.VELOCITY_H_MAX;
import static com.googlecode.tda367.denty.constants.DynamicConstant.VELOCITY_V_INC;
import static com.googlecode.tda367.denty.constants.DynamicConstant.VELOCITY_V_MAX;
import static com.googlecode.tda367.denty.constants.Hit.DENTY;
import static com.googlecode.tda367.denty.constants.Hit.THROWABLE_BLOCK;
import static com.googlecode.tda367.denty.constants.Hit.THROWABLE_BLOCK_HIGH_SPEED;
import static com.googlecode.tda367.denty.constants.StateConstant.MOVING_LEFT;
import static com.googlecode.tda367.denty.constants.StateConstant.MOVING_RIGHT;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;

import com.googlecode.tda367.denty.constants.DynamicConstant;
import com.googlecode.tda367.denty.constants.Hit;
import com.googlecode.tda367.denty.constants.StateConstant;
import com.googlecode.tda367.denty.core.data.GameData;
import com.googlecode.tda367.denty.util.PhysicalBodiesUtil;

public class ThrowableBlock implements MoveableBody {
	private InnerBody body;
	
	public ThrowableBlock(World world, float x, float y) {
		Body physicalBody = this.createPhysicalRepresentation(world, new Vec2(x,y));
		this.body = new InnerBody(physicalBody);
		this.defineConstants();
	}
	
	private Body createPhysicalRepresentation(World world, Vec2 position){
		BodyDef bodyDef = PhysicalBodiesUtil.createBodyDef(position, BodyType.DYNAMIC, this);
		PolygonShape shape = PhysicalBodiesUtil.createBoxShape();
		FixtureDef fixtureDef = PhysicalBodiesUtil.createFixtureDef(shape, 0.2f, 0.2f);
		Body body = PhysicalBodiesUtil.createBody(world, bodyDef, fixtureDef);
		return body;
	}
	
	private void defineConstants(){
		this.body.addDynamicConstant(VELOCITY_H_MAX, 8);
		this.body.addDynamicConstant(VELOCITY_H_INC, 2);
		this.body.addDynamicConstant(VELOCITY_V_MAX, 8);
		this.body.addDynamicConstant(VELOCITY_V_INC, 2);
		
		this.body.addAllowedState(MOVING_LEFT);
		this.body.addAllowedState(MOVING_RIGHT);
	}
	
	@Override
	public Vec2 getPosition(){
		return new Vec2(this.body.getPosition());
	}

	@Override
	public Vec2 getLinearVelocity() {
		return new Vec2(this.body.getLinearVelocity());
	}

	@Override
	public void applyForce(Vec2 force) {
		this.body.applyForce(force);
	}

	@Override
	public void applyVelocity(Vec2 velocity) {
		this.body.applyVelocity(velocity);
	}

	@Override
	public float getRotation() {
		return this.body.getRotation();
	}

	@Override
	public float getConstant(DynamicConstant dc) {
		return this.body.getConstant(dc);
	}

	@Override
	public boolean getState(StateConstant sc) {
		return this.body.getState(sc);
	}

	@Override
	public void setState(StateConstant sc, boolean b) {
		this.body.setState(sc, b);
	}

	@Override
	public void beginContact(Fixture hitFixture, Collection<Hit> hitConstants) {
		GameData gameData = GameData.getInstance();
		if (hitConstants.contains(DENTY) && !this.getHitConstants(hitFixture).contains(THROWABLE_BLOCK_HIGH_SPEED)
				&& this.isAlive() && gameData.getBlocks() < gameData.getMaxBlocks()) {
			this.setAlive(false);
			gameData.setBlocks(gameData.getBlocks() +1);
		}
	}

	@Override
	public Collection<Hit> getHitConstants(Fixture fixture) {
		List<Hit> hitConstants = new ArrayList<Hit>();
		hitConstants.add(THROWABLE_BLOCK);
		Vec2 linV = this.getLinearVelocity();
		double velocity = Math.sqrt(linV.x*linV.x + linV.y * linV.y);
		// TODO Which velocity to be required for counting as a hit that does damage
		// has to be tested
		if (velocity > 15) {
			hitConstants.add(THROWABLE_BLOCK_HIGH_SPEED);
		}
		return hitConstants;
	}

	@Override
	public void destroy() {
		this.body.destroy();
	}

	@Override
	public boolean isAlive() {
		return this.body.isAlive();
	}
	
	public void setAlive(boolean value){
		this.body.setAlive(value);
	}

	@Override
	public String getImagePath() {
		return "res/img/block.png";
	}

	@Override
	public void endContact(Fixture hitFixture, Collection<Hit> hitConstants) {
		// TODO Auto-generated method stub
		
	}
}
